home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
os2
/
plnk081.zip
/
pilot-link.0.8.1
/
libsock
/
unixserial.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-06-29
|
8KB
|
401 lines
/* unixserial.c: tty line interface code for Pilot serial comms under UNIX
*
* Copyright (c) 1996, 1997, D. Jeff Dionne & Kenneth Albanowski.
* This is free software, licensed under the GNU Public License V2.
* See the file COPYING for details.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include "pi-source.h"
#include "pi-socket.h"
#include "pi-serial.h"
#include "pi-slp.h"
#include "pi-syspkt.h"
#include "pi-padp.h"
/* if this is running on a NeXT system... */
#ifdef NeXT
#include <sys/uio.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/file.h>
#include <fcntl.h>
#endif
#ifdef HAVE_SYS_IOCTL_COMPAT_H
#include <sys/ioctl_compat.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifndef SGTTY
#ifndef HAVE_CFMAKERAW
#define cfmakeraw(ptr) (ptr)->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR\
|IGNCR|ICRNL|IXON);\
(ptr)->c_oflag &= ~OPOST;\
(ptr)->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);\
(ptr)->c_cflag &= ~(CSIZE|PARENB);\
(ptr)->c_cflag |= CS8
#endif
#ifndef HAVE_CFSETSPEED
#if defined(HAVE_CFSETISPEED) && defined(HAVE_CFSETOSPEED)
#define cfsetspeed(t,speed) \
(cfsetispeed(t,speed) || cfsetospeed(t,speed))
#else
static int cfsetspeed(struct termios * t,int speed) {
#ifdef HAVE_TERMIOS_CSPEED
t->c_ispeed=speed;
t->c_ospeed=speed;
#else
t->c_cflag|=speed;
#endif
return 0;
}
#endif
#endif
#endif /*SGTTY*/
static int calcrate(int baudrate) {
#ifdef B300
if(baudrate == 300) return B300;
#endif
#ifdef B1200
if(baudrate == 1200) return B1200;
#endif
#ifdef B2400
if(baudrate == 2400) return B2400;
#endif
#ifdef B4800
if(baudrate == 4800) return B4800;
#endif
#ifdef B9600
if(baudrate == 9600) return B9600;
#endif
#ifdef B19200
else if(baudrate == 19200) return B19200;
#endif
#ifdef B38400
else if(baudrate == 38400) return B38400;
#endif
#ifdef B57600
else if(baudrate == 57600) return B57600;
#endif
#ifdef B115200
else if(baudrate == 115200) return B115200;
#endif
#ifdef B230400
else if(baudrate == 230400) return B230400;
#endif
#ifdef B460800
else if(baudrate == 460800) return B460800;
#endif
else {
printf("Unable to set baud rate %d\n", baudrate);
abort(); /* invalid baud rate */
}
}
#ifndef O_NONBLOCK
# define O_NONBLOCK 0
#endif
static int s_changebaud(struct pi_socket *ps);
static int s_close(struct pi_socket *ps);
static int s_write(struct pi_socket *ps);
static int s_read(struct pi_socket *ps, int timeout);
int pi_serial_open(struct pi_socket *ps, struct pi_sockaddr * addr, int addrlen)
{
char * tty = addr->pi_device;
int i;
#ifndef SGTTY
struct termios tcn;
#else
struct sgttyb tcn;
#endif
if ((!tty) || !strlen(tty))
tty = getenv("PILOTPORT");
if (!tty)
tty = "<Null>";
if ((ps->mac->fd = open(tty, O_RDWR | O_NONBLOCK )) == -1) {
return -1; /* errno already set */
}
if (!isatty(ps->mac->fd)) {
close(ps->mac->fd);
errno = EINVAL;
return -1;
}
#ifndef SGTTY
/* Set the tty to raw and to the correct speed */
tcgetattr(ps->mac->fd,&tcn);
ps->tco = tcn;
tcn.c_oflag = 0;
tcn.c_iflag = IGNBRK | IGNPAR;
tcn.c_cflag = CREAD | CLOCAL | CS8;
(void)cfsetspeed(&tcn, calcrate(ps->rate));
tcn.c_lflag = NOFLSH;
cfmakeraw(&tcn);
for(i=0;i<16;i++) tcn.c_cc[i]=0;
tcn.c_cc[VMIN] = 1;
tcn.c_cc[VTIME] = 0;
tcsetattr(ps->mac->fd,TCSANOW,&tcn);
#else
/* Set the tty to raw and to the correct speed */
ioctl(ps->mac->fd, TIOCGETP, &tcn);
ps->tco = tcn;
tcn.sg_flags = RAW;
tcn.sg_ispeed = calcrate(ps->rate);
tcn.sg_ospeed = calcrate(ps->rate);
ioctl(ps->mac->fd, TIOCSETN, &tcn);
#endif
if ((i = fcntl(ps->mac->fd, F_GETFL, 0))!=-1) {
i &= ~O_NONBLOCK;
fcntl(ps->mac->fd, F_SETFL, i);
}
if (ps->sd) {
int orig = ps->mac->fd;
#ifdef HAVE_DUP2
ps->mac->fd = dup2(ps->mac->fd, ps->sd);
#else
#ifdef F_DUPFD
close(ps->sd);
ps->mac->fd = fcntl(ps->mac->fd, F_DUPFD, ps->sd);
#else
close(ps->sd);
ps->mac->fd = dup(ps->mac->fd); /* Unreliable */
#endif
#endif
if (ps->mac->fd != orig)
close(orig);
}
#ifndef NO_SERIAL_TRACE
if(ps->debuglog) {
ps->debugfd = open(ps->debuglog,O_WRONLY|O_CREAT|O_APPEND,0666);
/* This sequence is magic used by my trace analyzer - kja */
write(ps->debugfd, "\0\1\0\0\0\0\0\0\0\0", 10);
}
#endif
ps->serial_close = s_close;
ps->serial_read = s_read;
ps->serial_write = s_write;
ps->serial_changebaud = s_changebaud;
return ps->mac->fd;
}
/* Linux versions "before 2.1.8 or so" fail to flush hardware FIFO on port close */
#ifdef linux
# ifndef LINUX_VERSION_CODE
# include <linux/version.h>
# endif
# ifndef LINUX_VERSION_CODE
# define sleeping_beauty
# else
# if (LINUX_VERSION_CODE < 0x020108)
# define sleeping_beauty
# endif
# endif
#endif
/* Unspecified NetBSD versions fail to flush hardware FIFO on port close */
#ifdef __NetBSD__
# define sleeping_beauty
#endif
/* SGI IRIX fails to flush hardware FIFO on port close */
#ifdef __sgi
# define sleeping_beauty
#endif
static int s_changebaud(struct pi_socket *ps)
{
#ifndef SGTTY
struct termios tcn;
#ifdef sleeping_beauty
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 50000;
select(0,0,0,0, &tv);
#endif
/* Set the tty to the new speed */
tcgetattr(ps->mac->fd,&tcn);
tcn.c_cflag = CREAD | CLOCAL | CS8;
(void)cfsetspeed(&tcn, calcrate(ps->rate));
tcsetattr(ps->mac->fd,TCSADRAIN,&tcn);
#ifdef sleeping_beauty
tv.tv_sec = 0;
tv.tv_usec = 50000;
select(0,0,0,0, &tv);
#endif
#else
struct sgttyb tcn;
ioctl(ps->mac->fd, TIOCGETP, &tcn);
tcn.sg_ispeed = calcrate(ps->rate);
tcn.sg_ospeed = calcrate(ps->rate);
ioctl(ps->mac->fd, TIOCSETN, &tcn);
#endif
return 0;
}
static int s_close(struct pi_socket *ps)
{
int result;
#ifndef SGTTY
tcsetattr(ps->mac->fd,TCSADRAIN, &ps->tco);
#else
ioctl(ps->mac->fd, TIOCSETP, &ps->tco);
#endif
result = close(ps->mac->fd);
ps->mac->fd = 0;
#ifndef NO_SERIAL_TRACE
if (ps->debugfd)
close(ps->debugfd);
#endif
return result;
}
static int s_write(struct pi_socket *ps)
{
struct pi_skb *skb;
int nwrote, len;
#ifndef NO_SERIAL_TRACE
int i;
#endif
if (ps->txq) {
ps->busy++;
skb = ps->txq;
ps->txq = skb->next;
len = 0;
while (len<skb->len) {
nwrote = 0;
nwrote=write(ps->mac->fd,skb->data,skb->len);
if (nwrote<=0)
break; /* transmission failure */
len += nwrote;
}
#ifndef NO_SERIAL_TRACE
if (ps->debuglog)
for (i=0;i<skb->len;i++) {
write(ps->debugfd, "2", 1);
write(ps->debugfd, skb->data+i, 1);
}
#endif
ps->tx_bytes += skb->len;
free(skb);
ps->busy--;
return 1;
}
return 0;
}
static int s_read(struct pi_socket *ps, int timeout)
{
int r;
unsigned char *buf;
#ifndef NO_SERIAL_TRACE
int i;
#endif
fd_set ready,ready2;
struct timeval t;
FD_ZERO(&ready);
FD_SET(ps->mac->fd, &ready);
/* FIXME: if timeout == 0, wait forever for packet, otherwise wait till
timeout tenth-of-seconds */
pi_serial_flush(ps); /* We likely want to be in sync with tx */
if (!ps->mac->expect) slp_rx(ps); /* let SLP know we want a packet */
while (ps->mac->expect) {
buf = ps->mac->buf;
while (ps->mac->expect) {
ready2 = ready;
t.tv_sec = timeout/10;
t.tv_usec = (timeout % 10) * 100000;
select(ps->mac->fd+1,&ready2,0,0,&t);
/* If data is available in time, read it */
if(FD_ISSET(ps->mac->fd,&ready2))
r = read(ps->mac->fd, buf, ps->mac->expect);
else
{
/* otherwise throw out any current packet and return */
#ifdef DEBUG
fprintf(stderr, "Serial RX: timeout\n");
#endif
ps->mac->state = ps->mac->expect = 1;
ps->mac->buf = ps->mac->rxb->data;
ps->rx_errors++;
return 0;
}
#ifndef NO_SERIAL_TRACE
if (ps->debuglog)
for (i=0;i<r;i++) {
write(ps->debugfd, "1", 1);
write(ps->debugfd, buf+i, 1);
}
#endif
ps->rx_bytes += r;
buf += r;
ps->mac->expect -= r;
}
slp_rx(ps);
}
return 0;
}